home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / Libraries / TurboTCP 2.0.1 / TurboTCP source / CTCPEndpoint.cp < prev    next >
Encoding:
Text File  |  1994-07-04  |  23.7 KB  |  1,002 lines  |  [TEXT/MPCC]

  1. /*
  2. ** CTCPEndpoint.cp
  3. **
  4. **    TurboTCP support library
  5. **    TCP generic protocol interpreter
  6. **
  7. **    Copyright © 1993-94, FrostByte Design / Eric Scouten
  8. **
  9. */
  10.  
  11.  
  12. #include "CTCPEndpoint.h"
  13.  
  14. #include "CDecorator.h"
  15. #include "CError.h"
  16. #include "Constants.h"
  17. #include "Global.h"
  18. #include "TBUtilities.h"
  19. #include "TCLUtilities.h"
  20.  
  21. #include "CTCPDriver.h"
  22. #include "CTCPResolverCall.h"
  23. #include "CTCPStream.h"
  24. #include "UTurboTCP.h"
  25.  
  26.  
  27. #define sessionOpen (cState >= strSYNReceived) && (cState <= strTimeWait)
  28. #define sessionOpening (cState >= strListen) && (cState <= strSYNSent)
  29. #define sessionClosing (cState >= strFINWait1) && (cState <= strTimeWait)
  30.  
  31.  
  32. #define ALRT_TCPOpenFailed    23000
  33. #define ALRT_TCPUnexpError    23001
  34. #define ALRT_TCPSendFailed    23002
  35. #define ALRT_TCPTerminated    23003
  36. #define ESTR_TerminBase        23010
  37.  
  38. #define STR__WindowStrings    23000
  39. #define Wstr_NoSession         1
  40. #define Wstr_Separator         2
  41. #define Wstr_NotReadyPrefix     3
  42. #define Wstr_NotReadySuffix     4
  43. #define Wstr_Untitled         5
  44. #define Wstr_PortDelimiter     6
  45.  
  46. extern CDecorator*    gDecorator;
  47. extern CError*        gError;
  48.  
  49. TCL_DEFINE_CLASS_M0(CTCPEndpoint);
  50.  
  51.  
  52. //    —— constructor/destructor ——
  53.  
  54. /*______________________________________________________________________
  55. **
  56. ** constructor
  57. **
  58. **    Initialize the protocol interpreter.
  59. **
  60. **        theDefaultPort (unsigned short):    default IP port number (the only required parameter)
  61. **        recBufferSize (unsigned long):        size of receive buffer to create
  62. **        autoReceiveSize (unsigned short):    number of entries in RDS for auto-receive,
  63. **                                        0 to disable autoreceiving
  64. **        autoReceiveNum (unsigned short):    number of auto-receive calls to issue at once
  65. **                                        must be at least 1
  66. **        doUseCName (Boolean):            TRUE to get canonical name of remote host
  67. **                                        whenever possible
  68. **
  69. */
  70.  
  71. CTCPEndpoint::CTCPEndpoint(unsigned short theDefaultPort, unsigned long recBufferSize,
  72.                         unsigned short autoReceiveSize, unsigned short autoReceiveNum,
  73.                         Boolean doUseCName)
  74.  
  75. {
  76.  
  77.     // blank out the usual variables
  78.     
  79.     itsStream = NULL;
  80.     itsResolver = NULL;
  81.     pendingOpenByName = closeAndQuit = FALSE;
  82.     actualPort = defaultPort = theDefaultPort;
  83.     hostCName[0] = '\0';
  84.     useCName = doUseCName;
  85.     goAwayOnClose = FALSE;
  86.     showFileName = TRUE;
  87.     showHostName = TRUE;
  88.     untitledNumber = 0;
  89.     localPort = 0;
  90.  
  91.  
  92.     // create a TCP stream
  93.  
  94.     TRY {
  95.         itsStream = new CTCPStream(*this, recBufferSize, autoReceiveSize, autoReceiveNum);
  96.         itsResolver = new CTCPResolverCall(*this);
  97.     }
  98.     
  99.     CATCH {
  100.         if (itsStream)
  101.             itsStream->Dispose();
  102.         itsStream = NULL;
  103.         if (itsResolver)
  104.             itsResolver->Dispose();
  105.         itsResolver = NULL;
  106.     }
  107.     
  108.     ENDTRY;
  109.     
  110. }
  111.  
  112. /*______________________________________________________________________
  113. **
  114. ** destructor
  115. **
  116. **    Get rid of the stream and resolver objects.
  117. **
  118. */
  119.  
  120. CTCPEndpoint::~CTCPEndpoint()
  121.  
  122. {
  123.     if (itsStream)
  124.         itsStream->Dispose();
  125.     if (itsResolver)
  126.         itsResolver->Dispose();
  127. }
  128.  
  129.  
  130. //    —— opening/closing session ——
  131.  
  132. /*______________________________________________________________________
  133. **
  134. ** OpenUserHost
  135. **
  136. **    Open a connection to the host named by the string. Hostname may be either dotted decimal
  137. **    notation or a DNS name. A port number may be specified at the end of the hostname
  138. **    (separated by a single space) if the caller permits it.
  139. **
  140. **        theHostName (char*):            the hostname (and optional port#) string
  141. **        theDefaultPort (unsigned short):    the default port number
  142. **        allowPortChange (Boolean):        TRUE to allow port number overrides
  143. **
  144. */
  145.  
  146. void CTCPEndpoint::OpenUserHost(char* theHostName, unsigned short theDefaultPort,
  147.                                 Boolean allowPortChange)
  148.  
  149. {
  150.     Str255        portNumStr;
  151.     long            newPortNum = 0;
  152.     register char*    s;
  153.     register char*    d;
  154.     register short    i;
  155.  
  156.  
  157.     // ensure that there is a host to open
  158.     
  159.     if (*theHostName == '\0') {
  160.         HandleOpenFailed(nameSyntaxErr);
  161.         return;
  162.     }
  163.  
  164.  
  165.     // parse for port number
  166.     
  167.     pendingPortNumber = theDefaultPort;
  168.     if (allowPortChange) {
  169.         s = theHostName;
  170.         d = (char*) &hostCName;
  171.         while ((*s != ' ') & (*s != '\0'))
  172.             *d++ = *s++;
  173.         *d = '\0';
  174.         if (*s == ' ') {
  175.             d = (char*) &portNumStr;
  176.             i = -1;
  177.             while (*s != '\0')
  178.                 *d++ = *s++, i++;
  179.             portNumStr[0] = (char) i;
  180.             if (i > 0)
  181.                 StringToNum(portNumStr, &newPortNum);
  182.         }
  183.     }
  184.     else
  185.         BlockMove(theHostName, &hostCName, 255);
  186.     
  187.     if (newPortNum != 0)
  188.         pendingPortNumber = newPortNum;
  189.  
  190.  
  191.     // issue resolver command
  192.     
  193.     pendingOpenByName = TRUE;
  194.     actualPort = pendingPortNumber;
  195.     itsResolver->DoStrToAddr((char*) &hostCName);
  196.     
  197. }
  198.  
  199.  
  200. /*______________________________________________________________________
  201. **
  202. ** OpenHost
  203. **
  204. **    Open a connection to the host named by the IP address and port number specified.
  205. **    This routine provides a way to bypass the DNR when opening connections. If the
  206. **    doUseCName option was specified when the object was constructed, this method will
  207. **    issue a DNR call to obtain the remote host’s canonical name.
  208. **
  209. **        remoteHostIP (unsigned long):        the remote host’s address
  210. **        remoteHostPort (unsigned short):    the remote host’s port number
  211. **
  212. */
  213.  
  214. void CTCPEndpoint::OpenHost(unsigned long remoteHostIP, unsigned short remoteHostPort)
  215.  
  216. {
  217.  
  218.     // open the connection
  219.     
  220.     pendingOpenByName = TRUE;
  221.     itsStream->OpenConnection(FALSE, remoteHostIP, remoteHostPort, localPort);
  222.  
  223.  
  224.     // set window title to dotted IP address until we can get the canonical name
  225.  
  226.     itsResolver->DoAddrToStr(remoteHostIP, hostCName);
  227.     StateChanged();
  228.  
  229.  
  230.     // if desired, get the canonical name
  231.     
  232.     if (useCName) {
  233.         itsResolver->DoAddrToName(hostAddress);
  234.         pendingOpenByName = TRUE;
  235.     }
  236.  
  237. }
  238.  
  239.  
  240. /*______________________________________________________________________
  241. **
  242. ** Listen
  243. **
  244. **    Initiate a “passive open” command. Wait for a remote host to attempt to connect to this
  245. **    machine. If the connection is to come from a specific host, the host’s IP address must be
  246. **    specified and the port number may be specified. If the connection may come from any host,
  247. **    both the IP address and port number must be left blank.
  248. **
  249. **        remoteHostIP (unsigned long):        the remote host’s address
  250. **        remoteHostPort (unsigned short):    the remote host’s port number
  251. **
  252. */
  253.  
  254. void CTCPEndpoint::Listen(unsigned long remoteHostIP, unsigned short remoteHostPort)
  255.  
  256. {
  257.     pendingOpenByName = TRUE;
  258.     itsStream->OpenConnection(TRUE, remoteHostIP, remoteHostPort, localPort);
  259. }
  260.  
  261.  
  262. /*______________________________________________________________________
  263. **
  264. ** LocalClose
  265. **
  266. **    Use this method when the user clicks the close box, or your application is done with
  267. **    this session. Ensures that the TCP stream is gracefully closed. If not quitting, delays
  268. **    closure until MacTCP says the stream has been terminated. Note that this method
  269. **    has the same interface as the CDirector::Close.
  270. **
  271. **    This method is not called by the CTCPEndpoint class and need not be overriden.
  272. **
  273. **        quitting (Boolean):    TRUE if quitting
  274. **
  275. **        return (Boolean):    FALSE if close/quit should be aborted
  276. **
  277. */
  278.  
  279. Boolean CTCPEndpoint::LocalClose(Boolean quitting)
  280.  
  281. {
  282.     Boolean        hadSessionOpen;
  283.     unsigned short    cState;
  284.  
  285.  
  286.     // if session is open, give time for session to close
  287.     
  288.     if (itsStream) {
  289.         cState = itsStream->ConnectionState();
  290.         hadSessionOpen = sessionOpen;
  291.         if (sessionOpen)
  292.             itsStream->Close();
  293.         if (sessionOpening)
  294.             itsStream->Abort();
  295.     }
  296.     else
  297.         hadSessionOpen = FALSE;
  298.  
  299.  
  300.     // close the document – maybe?
  301.     
  302.     return (quitting || !hadSessionOpen || !goAwayOnClose);
  303.  
  304. }
  305.  
  306.  
  307. /*______________________________________________________________________
  308. **
  309. ** SessionEstablished
  310. **
  311. **    Indicates whether a TCP session is established and ready for data.
  312. **
  313. **        return (Boolean):    TRUE if session is currently established
  314. **
  315. */
  316.  
  317. Boolean CTCPEndpoint::SessionEstablished()
  318.  
  319. {
  320.     if (itsStream)
  321.         return (itsStream->ConnectionState() == strEstablished);
  322.     else
  323.         return FALSE;
  324. }
  325.  
  326.  
  327. //    —— sending data ——
  328.  
  329. /*______________________________________________________________________
  330. **
  331. ** SendBfrCpy
  332. **
  333. **    Send bytes to the TCP stream. Copies the data to a buffer which can persist beyond the
  334. **    function or object which generated the data.
  335. **
  336. **        theData (const void*):        the bytes to send
  337. **        theDataSize (unsigned short):    number of bytes to send
  338. **
  339. */
  340.  
  341. void CTCPEndpoint::SendBfrCpy(const void* theData, unsigned short theDataSize)
  342.  
  343. {
  344.     itsStream->SendBfrCpy(theData, theDataSize);
  345. }
  346.  
  347.  
  348. /*______________________________________________________________________
  349. **
  350. ** SendBfrNoCpy
  351. **
  352. **    Send bytes to the TCP stream. Does not copy the data. The caller is responsible for
  353. **    ensuring that the data are available until the call is completed. You may detect the safe
  354. **    transmittal of your data by overriding the HandleDataSent() method and comparing
  355. **    pointers. You may also request that the data be disposed (using the DisposPtr routine)
  356. **    when the call completes by setting disposeWhenDone to TRUE.
  357. **
  358. **        theData (const void*):        the bytes to send
  359. **        theDataSize (unsigned short):    number of bytes to send
  360. **        disposeWhenDone (Boolean):    set to TRUE to dispose of the buffer (DisposPtr)
  361. **                                    when completed (only if this pointer was
  362. **                                    allocated as a pointer, not a handle deref)
  363. **        notifyWhenDone (Boolean):    set to TRUE to notify the endpoint object
  364. **                                    when completed (via HandleDataSent or
  365. **                                    HandleSendFailed)
  366. **
  367. */
  368.  
  369. void CTCPEndpoint::SendBfrNoCpy(const void* theData, unsigned short theDataSize,
  370.                             Boolean disposeWhenDone, Boolean notifyWhenDone)
  371.  
  372. {
  373.     itsStream->SendBfrNoCpy(theData, theDataSize, disposeWhenDone, notifyWhenDone);
  374. }
  375.  
  376.  
  377. /*______________________________________________________________________
  378. **
  379. ** SendChar
  380. **
  381. **    Send a single character to the TCP stream.
  382. **
  383. **        theChar (char):        the character to send
  384. **
  385. */
  386.  
  387. void CTCPEndpoint::SendChar(const char theChar)
  388.  
  389. {
  390.     SendBfrCpy(&theChar, 1);
  391. }
  392.  
  393.  
  394. /*______________________________________________________________________
  395. **
  396. ** SendCString
  397. **
  398. **    Send a C string to the TCP stream.
  399. **
  400. **        theString (char*):    the string to send
  401. **
  402. */
  403.  
  404. void CTCPEndpoint::SendCString(const char* theString)
  405.  
  406. {
  407.     SendBfrCpy(theString, cstrlen((char*) theString));
  408. }
  409.  
  410.  
  411. /*______________________________________________________________________
  412. **
  413. ** SendPString
  414. **
  415. **    Send a Pascal string to the TCP stream.
  416. **
  417. **        theString (unsigned char* ):    the string to send
  418. **
  419. */
  420.  
  421. void CTCPEndpoint::SendPString(const unsigned char* theString)
  422.  
  423. {
  424.     SendBfrCpy((char*) theString + 1, theString[0]);
  425. }
  426.  
  427.  
  428. /*______________________________________________________________________
  429. **
  430. ** SetNextPush
  431. **
  432. **    The next data will be send with the “push” flag set.
  433. **
  434. */
  435.  
  436. void CTCPEndpoint::SetNextPush()
  437.  
  438. {
  439.     itsStream->SetNextPush();
  440. }
  441.  
  442.  
  443. /*______________________________________________________________________
  444. **
  445. ** SetNextUrgent
  446. **
  447. **    The next data will be send with the “urgent” flag set.
  448. **
  449. */
  450.  
  451. void CTCPEndpoint::SetNextUrgent()
  452.  
  453. {
  454.     itsStream->SetNextUrgent(FALSE);
  455. }
  456.  
  457.  
  458. /*______________________________________________________________________
  459. **
  460. ** endl (manipulator for CTCPEndpoint)
  461. **
  462. **    Send end-of-line character.
  463. **
  464. */
  465.  
  466. CTCPEndpoint& endl(CTCPEndpoint& ep)
  467. {
  468.     ep.SendChar('\r');
  469.     return ep;
  470. }
  471.  
  472.  
  473. /*______________________________________________________________________
  474. **
  475. ** local_IP (manipulator for CTCPEndpoint)
  476. **
  477. **    Send local IP address in dotted IP format.
  478. **
  479. */
  480.  
  481. CTCPEndpoint& local_IP(CTCPEndpoint& ep)
  482. {
  483.     char ip_addr[16];
  484.     UTurboTCP::DoAddrToStr(ep.GetLocalHostIP(), ip_addr);
  485.     ep << ip_addr;
  486.     return ep;
  487. }
  488.  
  489.  
  490. /*______________________________________________________________________
  491. **
  492. ** remote_IP (manipulator for CTCPEndpoint)
  493. **
  494. **    Send remote IP address in dotted IP format.
  495. **
  496. */
  497.  
  498. CTCPEndpoint& remote_IP(CTCPEndpoint& ep)
  499. {
  500.     char ip_addr[16];
  501.     UTurboTCP::DoAddrToStr(ep.GetRemoteHostIP(), ip_addr);
  502.     ep << ip_addr;
  503.     return ep;
  504. }
  505.  
  506.  
  507. /*______________________________________________________________________
  508. **
  509. ** push (manipulator for CTCPEndpoint)
  510. **
  511. **    Send next data with “push” flag set.
  512. **
  513. */
  514.  
  515. CTCPEndpoint& push(CTCPEndpoint& ep)
  516.  
  517. {
  518.     ep.SetNextPush();
  519.     return ep;
  520. }
  521.  
  522.  
  523. /*______________________________________________________________________
  524. **
  525. ** urgent (manipulator for CTCPEndpoint)
  526. **
  527. **    Send next data with “urgent” flag set.
  528. **
  529. */
  530.  
  531. CTCPEndpoint& urgent(CTCPEndpoint& ep)
  532.  
  533. {
  534.     ep.SetNextUrgent();
  535.     return ep;
  536. }
  537.  
  538.  
  539. //    —— configuration methods ——
  540.  
  541. /*______________________________________________________________________
  542. **
  543. **    Use these methods to set various IP parameters for the next connection built on this
  544. **    endpoint. If a session has been opened already on this endpoint, these methods will have
  545. **    no effect on the current session.
  546. **
  547. */
  548.  
  549. void CTCPEndpoint::SetDefaultPort(unsigned short newDefaultPort)            // set default remot host port
  550.     { defaultPort = newDefaultPort; }
  551. void CTCPEndpoint::SetLocalHostPort(unsigned short newLocalPort)            // set a new local host port for next connection
  552.     { localPort = newLocalPort; }
  553. void CTCPEndpoint::SetOpenTimeout(unsigned short openMaxSeconds)        // max time to establish session for next connection
  554.     { itsStream->SetULPTimeoutValue(openMaxSeconds); }
  555. void CTCPEndpoint::SetListenTimeout(unsigned short openMaxSeconds)        // max time to wait for passive connection
  556.     { itsStream->SetCommandTimeout((short) openMaxSeconds); }
  557. void CTCPEndpoint::SetTypeOfService(Boolean lowDelay,                    // set type of service for next connection
  558.         Boolean highThroughput, Boolean highReliability)
  559.     { itsStream->SetTypeOfService((lowDelay ? 0x01 : 0) |
  560.         (highThroughput ? 0x02 : 0) | (highReliability ? 0x04 : 0)); }
  561. void CTCPEndpoint::SetPrecedence(TCPPrecedence newPrecedence)            // set precedence for next connection
  562.     { itsStream->SetPrecedence((short) newPrecedence); }
  563. void CTCPEndpoint::SetDontFragment(Boolean newDontFragment)            // set/clear don’t fragment for next connection
  564.     { itsStream->SetDontFrag((short) newDontFragment); }
  565. void CTCPEndpoint::SetTimeToLive(unsigned short newTimeToLive)            // maximum hop count for IP connection
  566.     { itsStream->SetTimeToLive(newTimeToLive); }
  567. void CTCPEndpoint::SetSecurity(unsigned short newSecurity)                // security flag
  568.     { itsStream->SetSecurity(newSecurity); }
  569.  
  570.  
  571. //    —— selectors ——
  572.  
  573. /*______________________________________________________________________
  574. **
  575. **    Use these methods to get information on the current endpoint and connection.
  576. **
  577. */
  578.  
  579. void CTCPEndpoint::GetRemoteHostName(char* hostStringBfr)                // get the name of the remote host machine
  580.     { BlockMove(hostCName, hostStringBfr, cstrlen(hostCName)); }
  581. unsigned long CTCPEndpoint::GetRemoteHostIP()
  582.     { return hostAddress; }
  583. unsigned short CTCPEndpoint::GetRemoteHostPort()
  584.     { return actualPort; }
  585. unsigned long CTCPEndpoint::GetLocalHostIP()
  586.     { return UTurboTCP::GetLocalIPAddr(); }
  587. unsigned short CTCPEndpoint::GetLocalHostPort()
  588.     { return localPort; }
  589. unsigned short CTCPEndpoint::GetDefaultPort()
  590.     { return defaultPort; }
  591.  
  592.  
  593. //    —— state change notifications ——
  594.  
  595. /*______________________________________________________________________
  596. **
  597. ** RemoteClose (protected method)
  598. **
  599. **    This method is called when the remote host closes or aborts a session. Override this
  600. **    to ensure that your windows are closed or the user is somehow notified. (Be sure to
  601. **    call this method as well.)
  602. **
  603. */
  604.  
  605. void CTCPEndpoint::RemoteClose()
  606.  
  607. {
  608.     Boolean        hadSessionOpen;
  609.     unsigned short    cState;
  610.  
  611.  
  612.     // be sure to acknowledge the remote host’s intention to close
  613.  
  614.     if (itsStream) {
  615.         cState = itsStream->ConnectionState();
  616.         if (sessionOpen)
  617.             itsStream->Close();
  618.         if (sessionOpening)
  619.             itsStream->Abort();
  620.     }
  621. }
  622.  
  623.  
  624. /*______________________________________________________________________
  625. **
  626. ** StateChanged (protected method)
  627. **
  628. **    Called by other methods when the connection state changes (i.e. opens, aborts, or closes).
  629. **    Builds a new window title, then calls the SetWindowTitle() method to signal that the
  630. **    window’s title should be changed. 
  631. **
  632. **    If working with CDocument or CDialogDirector, SetWindowTitle() should look like this:
  633. **
  634. **        CYourClass::SetWindowTitle(Str255 newTitle)
  635. **        {
  636. **            if (itsWindow)
  637. **                itsWindow->SetTitle(newTitle);
  638. **        }
  639. **
  640. */
  641.  
  642. void CTCPEndpoint::StateChanged()
  643.  
  644. {
  645.     Str255    fileStr = "\p";
  646.     Str255    hostStr = "\p";
  647.     Str255    tempStr  = "\p";
  648.     Boolean    sessionReady = SessionEstablished();
  649.  
  650.  
  651.     // build document name string (if requested)
  652.     
  653.     if (showFileName) {
  654.         GetFileName(fileStr);
  655.         if (fileStr[0] == '\0') {
  656.             if (!untitledNumber)
  657.                 untitledNumber = gDecorator->GetWCount();
  658.             GetIndString(fileStr, STR__WindowStrings, Wstr_Untitled);
  659.             NumToString(untitledNumber, tempStr);
  660.             ConcatPStrings(fileStr, tempStr);
  661.         }
  662.     }
  663.  
  664.  
  665.     // build host name string
  666.  
  667.     if (showHostName) {
  668.         if (!hostCName[0])
  669.             GetIndString(hostStr, STR__WindowStrings, Wstr_NoSession);
  670.         else {
  671.             
  672.             if (!sessionReady)                        // left “(” if not ready
  673.                 GetIndString(hostStr, STR__WindowStrings, Wstr_NotReadyPrefix);
  674.                 
  675.             BlockMove(&hostCName, &tempStr, 255);    // host name, minus trailing “.”
  676.             CtoPstr((char*) &tempStr);
  677.             if (tempStr[tempStr[0]] == '.')
  678.                 tempStr[0]--;
  679.             ConcatPStrings(hostStr, tempStr);
  680.             
  681.             if (actualPort != defaultPort) {                // port number if non-standard
  682.                 GetIndString(tempStr, STR__WindowStrings, Wstr_PortDelimiter);
  683.                 ConcatPStrings(hostStr, tempStr);
  684.                 NumToString(actualPort, tempStr);
  685.                 ConcatPStrings(hostStr, tempStr);
  686.             }
  687.             
  688.             if (!sessionReady) {                        // right “)” if not ready
  689.                 GetIndString(tempStr, STR__WindowStrings, Wstr_NotReadySuffix);
  690.                 ConcatPStrings(hostStr, tempStr);
  691.             }
  692.             
  693.         }
  694.         
  695.         if (showFileName) {                            // “ : ” between file & host name
  696.             GetIndString(tempStr, STR__WindowStrings, Wstr_Separator);
  697.             ConcatPStrings(fileStr, tempStr);
  698.         }
  699.         ConcatPStrings(fileStr, hostStr);
  700.     }
  701.  
  702.  
  703.     // set the title
  704.  
  705.     if (showFileName || showHostName)                    // if neither file nor hostname are requested,
  706.                                                 //    assume subclass will specify window titles                    
  707.         SetWindowTitle(fileStr);
  708.     
  709. }
  710.  
  711.  
  712. //    —— error handling ——
  713.  
  714. /*______________________________________________________________________
  715. **
  716. ** TCPErrorAlert (protected method)
  717. **
  718. **    Display a customized message to indicate to the user that the connection failed. This
  719. **    routine is copied from the TCL’s routine ErrorAlert.
  720. **
  721. **        err (OSErr):        the error number
  722. **        message (long):        message code (same as for ErrorAlert, see <TCLUtilities.cp>
  723. **        alertID (short):        the ALRT/DITL resources to use
  724. **        parm3 (short):        the number to plug into ^3
  725. **
  726. **        return (short):        the item which caused the alert to return
  727. **
  728. */
  729.  
  730. short CTCPEndpoint::TCPErrorAlert(OSErr err, long message, short alertID, short parm3)
  731.  
  732. {
  733.     Str255    errStr;
  734.     Str255    hostStr;
  735.     Str63    numStr;
  736.     Str63    numStr3;
  737.     short    strIndex, strID;
  738.  
  739.  
  740.     // silence any further messages
  741.     
  742.     gLastError = kSilentErr;
  743.  
  744.  
  745.     // see if anyone filled in the message field
  746.     
  747.     errStr[0] = 0;
  748.     strIndex = LoShort(message);
  749.     
  750.     if (strIndex > 0) {
  751.         strID = HiShort(message);
  752.         if (strID == 0)
  753.             strID = STR_TCLfailMsgs;                // use built-in messages
  754.         else
  755.             strID += kUserFailMsgBase;            // use user’s message STR#
  756.         GetIndString(errStr, strID, strIndex);
  757.     }
  758.  
  759.  
  760.     // if still no message, check for 'Estr' resource
  761.         
  762.     if (errStr[0] == 0) {
  763.         StringHandle strH;
  764.          
  765.         strH = (StringHandle) GetResource(ErrMsg_Res, err);
  766.         if (!strH)
  767.              strH = GetString(STRosError2);
  768.          if (strH)
  769.              CopyPString(*strH, errStr);
  770.     }
  771.  
  772.  
  773.     // convert Mac error# and user’s host name to strings
  774.             
  775.     NumToString(err, numStr);
  776.     NumToString(parm3, numStr3);
  777.  
  778.     BlockMove(&hostCName, &hostStr, 255);
  779.     CtoPstr((char*) &hostStr);
  780.     if (hostStr[hostStr[0]] == '.')
  781.         hostStr[0]--;
  782.  
  783.     ParamText(errStr, numStr, hostStr, numStr3);
  784.  
  785.  
  786.     // avoid infinite recursion in error handling by specifically
  787.     //    testing if the ALRT and DITL resources we need are there
  788.         
  789.       if ((GetResource('ALRT', alertID) == NULL) ||
  790.           (GetResource('DITL', alertID) == NULL))
  791.       {
  792.           if (gError)
  793.                gError->MissingResources();
  794.            else
  795.                ExitToShell();            // nothing else we can do...
  796.        }
  797.    
  798.    
  799.        // show the error alert
  800.  
  801.     PositionDialog('ALRT', alertID);
  802.     InitCursor();
  803.     return StopAlert(alertID, NULL);
  804.  
  805. }
  806.  
  807.  
  808. //    —— TCP/DNR notification routines ——
  809.  
  810. /*______________________________________________________________________
  811. **
  812. ** HandleClosing (protected method)
  813. **
  814. **    Respond to notification that the session is being closed.
  815. **
  816. **        remoteClosing (Boolean):    TRUE if close initiated by remote host
  817. **
  818. */
  819.  
  820. void CTCPEndpoint::HandleClosing(Boolean remoteClosing)
  821.  
  822. {
  823.     StateChanged();
  824.     if (remoteClosing)
  825.         RemoteClose();
  826. }
  827.  
  828.  
  829. /*______________________________________________________________________
  830. **
  831. ** HandleOpened (protected method)
  832. **
  833. **    Respond to successful completion of a TCPPassiveOpen or TCPActiveOpen command.
  834. **
  835. */
  836.  
  837. void CTCPEndpoint::HandleOpened()
  838.  
  839. {
  840.     actualPort = itsStream->itsRemotePort;
  841.     StateChanged();
  842. }
  843.  
  844.  
  845. /*______________________________________________________________________
  846. **
  847. ** HandleOpenFailed (protected method)
  848. **
  849. **    Respond to notification that a TCPOpen command failed.
  850. **
  851. **        theResultCode (OSErr):    the reason for failure
  852. */
  853.  
  854. void CTCPEndpoint::HandleOpenFailed(OSErr theResultCode)
  855.  
  856. {
  857.     TCPErrorAlert(theResultCode, 0L, ALRT_TCPOpenFailed, 1);
  858.     RemoteClose();
  859.     FailOSErr(kSilentErr);    
  860. }
  861.  
  862.  
  863. /*______________________________________________________________________
  864. **
  865. ** HandleTCPError (protected method)
  866. **
  867. **    Respond to failure of a TCP command that was not expected. Default method displays a
  868. **    dialog, but takes no other action.
  869. **
  870. **        theResultCode (OSErr):    the result code
  871. **        theCsCode (short):        the TCP command number that failed
  872. **
  873. */
  874.  
  875. void CTCPEndpoint::HandleTCPError(OSErr theResultCode, short theCsCode)
  876.  
  877. {
  878.     TCPErrorAlert(theResultCode, 0L, ALRT_TCPUnexpError, theCsCode);
  879. }
  880.  
  881.  
  882. /*______________________________________________________________________
  883. **
  884. ** HandleTerminated (protected method)
  885. **
  886. **    Respond to session termination event.
  887. **
  888. **        terminReason (unsigned short):        reason for termination (see TCP dev guide, p93)
  889. **        aboutToDispose (Boolean):            TRUE if TCP stream will now dispose of itself
  890. **
  891. */
  892.  
  893. void CTCPEndpoint::HandleTerminated(TCPTerminReason terminReason, Boolean aboutToDispose)
  894.  
  895. {
  896.  
  897.     // display error alert unless due to normal closure
  898.     
  899.     if ((terminReason != tcpTermAbort) && (terminReason != tcpTermClose))
  900.         TCPErrorAlert(terminReason + ESTR_TerminBase, 0L, ALRT_TCPTerminated, 0);
  901.  
  902.  
  903.     // retitle window & close if requested
  904.  
  905.     StateChanged();
  906.     RemoteClose();
  907.  
  908.  
  909.     // mark TCP stream as gone if appropriate
  910.     
  911.     if (aboutToDispose)
  912.         itsStream = NULL;
  913.  
  914. }
  915.  
  916.  
  917. /*______________________________________________________________________
  918. **
  919. ** HandleStrToAddr (protected method)
  920. **
  921. **    Respond to nofitication that a resolver StrToAddr call has completed. Most of this code
  922. **    is written to complete the OpenUserHost method. If OpenUserHost was issued, this method
  923. **    proceeds to establish a connection with the IP host which was named by the user.
  924. **
  925. **        theHostInfo (struct hostInfo*):    the hostInfo record (see MacTCP Dev Guide, p70)
  926. **
  927. */
  928.  
  929. void CTCPEndpoint::HandleStrToAddr(struct hostInfo* theHostInfo)
  930.  
  931. {
  932.  
  933.     // if OpenUserHost was issued, finish the job
  934.     
  935.     if ((pendingOpenByName) && (itsStream)) {
  936.         if ((*theHostInfo).rtnCode == noErr) {
  937.  
  938.  
  939.             // success, open the connection
  940.             
  941.             hostAddress = (*theHostInfo).addr[0];
  942.             pendingOpenByName = FALSE;
  943.             itsStream->OpenConnection(FALSE, hostAddress, pendingPortNumber, localPort);
  944.  
  945.  
  946.             // if desired, get the canonical name
  947.             
  948.             if (useCName) {
  949.                 if ((*theHostInfo).cname[0] == 0) {
  950.                     itsResolver->DoAddrToName(hostAddress);
  951.                     pendingOpenByName = TRUE;
  952.                 }
  953.                 else
  954.                     BlockMove(&(*theHostInfo).cname, &hostCName, 255);
  955.             }
  956.  
  957.  
  958.             // set the window title to reflect the name
  959.             
  960.             StateChanged();
  961.  
  962.         } else {
  963.  
  964.  
  965.             // failed, issue alert & quit
  966.  
  967.             pendingOpenByName = FALSE;
  968.             HandleOpenFailed((*theHostInfo).rtnCode);
  969.  
  970.         } // if (...noErr)
  971.     } // if (pendingOpenByName)
  972.     
  973. }
  974.  
  975.  
  976. /*______________________________________________________________________
  977. **
  978. ** HandleAddrToName (protected method)
  979. **
  980. **    Respond to nofitication that a resolver AddrToName call has completed.
  981. **
  982. **        theHostInfo (struct hostInfo*):    the hostInfo record (see MacTCP Dev Guide, p75)
  983. **
  984. */
  985.  
  986. void CTCPEndpoint::HandleAddrToName(struct hostInfo* theHostInfo)
  987.  
  988. {
  989.  
  990.     // if OpenUserHost was issued, grab the hostname
  991.     
  992.     if ((pendingOpenByName) && (useCName)) {
  993.         if ((*theHostInfo).rtnCode == noErr) {
  994.             pendingOpenByName = FALSE;
  995.             if ((*theHostInfo).cname[0])
  996.                 BlockMove(&(*theHostInfo).cname, &hostCName, 255);
  997.             StateChanged();
  998.         }
  999.     }
  1000.  
  1001. }
  1002.